package com.xiaouyudeguang.common.plugins;


import com.xiaouyudeguang.common.annotation.ApiLog;
import com.xiaouyudeguang.common.annotation.ApiMapping;
import com.xiaouyudeguang.common.annotation.ApiResource;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toCollection;
import static springfox.documentation.service.Tags.emptyTags;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 2001)
public class ApiTagsReader implements OperationBuilderPlugin {

    @Override
    public void apply(OperationContext context) {
        context.operationBuilder().tags(controllerTags(context));
    }

    private Set<String> controllerTags(OperationContext context) {
        Optional<ApiResource> controllerAnnotation = context.findControllerAnnotation(ApiResource.class);
        return controllerAnnotation
                .map(tagsFromController())
                .orElse(new HashSet<>());
    }

    private Set<String> operationTags(OperationContext context) {
        Optional<ApiMapping> apiMapping = context.findAnnotation(ApiMapping.class);
        Optional<ApiLog> apiLog = context.findAnnotation(ApiLog.class);
        return new HashSet<>(apiMapping.map(tagsFromApiMapping())
                .orElse(apiLog.map(tagsFromApiLog())
                        .orElse(new HashSet<>())));
    }

    private Function<ApiMapping, Set<String>> tagsFromApiMapping() {
        return input -> Stream.of(input.value())
                .filter(emptyTags())
                .collect(toCollection(TreeSet::new));
    }

    private Function<ApiLog, Set<String>> tagsFromApiLog() {
        return input -> Stream.of(input.tags())
                .filter(emptyTags())
                .collect(toCollection(TreeSet::new));
    }

    private Function<ApiResource, Set<String>> tagsFromController() {
        return input -> Stream.of(input.tags())
                .filter(emptyTags())
                .collect(toCollection(TreeSet::new));
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }
}
